/*
 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SE_NAPI_OMA_COMMON_H
#define SE_NAPI_OMA_COMMON_H

#include "napi/native_api.h"

#include <map>
#include "common_utils.h"
#include "napi/native_node_api.h"
#include "loghelper.h"

namespace OHOS {
namespace SE {
namespace OMAPI {

#define EMPTY_STR std::string("")

#define NAPI_SE_CALL_RETURN(func)                                          \
    do {                                                                   \
        napi_status ret = (func);                                          \
        if (ret != napi_ok) {                                              \
            ErrorLog("napi call function failed. ret:%{public}d", ret);    \
            return ret;                                                    \
        }                                                                  \
    } while (0)

#define NAPI_SE_RETURN_IF(condition, msg, ret)              \
    do {                                                    \
        if ((condition)) {                                  \
            ErrorLog(msg);                                  \
            return (ret);                                   \
        }                                                   \
    } while (0)

enum JS_ARGV_NUM : size_t {
    ARGV_NUM_0 = 0,
    ARGV_NUM_1 = 1,
    ARGV_NUM_2 = 2,
    ARGV_NUM_3 = 3,
    ARGV_NUM_4 = 4,
    ARGV_NUM_5 = 5,
};

enum JS_ARGV_INDEX : size_t {
    ARGV_INDEX_0 = 0,
    ARGV_INDEX_1,
    ARGV_INDEX_2,
    ARGV_INDEX_3,
    ARGV_INDEX_4,
};

// Exception code throw to application.
enum JSErrorCode : const int {
    ERR_SUCCESS = 0,

    // business error code, throw these errors to applcation.
    BUSI_ERR_PERM_EXCEPTION = 201,
    BUSI_ERR_PARAM_EXCEPTION = 401, // The parameter check failed.
    BUSI_ERR_CAPABILITY_EXCEPTION = 801, // Capability not supported.

    BUSI_ERR_SE_STATE_EXCEPTION = 3300101, // Illegal service state exception.
    BUSI_ERR_SE_ELEMENT_EXCEPTION = 3300102, // No such element exception.
    BUSI_ERR_SE_ACCESS_EXCEPTION = 3300103, // Illegal access rule exception.
    BUSI_ERR_SE_IO_EXCEPTION = 3300104,  // Secure element IO exception.
};

struct AsyncContext {
    napi_env env;
    napi_async_work work;
    napi_deferred deferred;
    napi_ref callbackRef = nullptr;
    napi_value result;
    bool resolved = false;
    int errorCode = 0;

    explicit AsyncContext(napi_env e, napi_async_work w = nullptr, napi_deferred d = nullptr)
        : env(e),
        work(w),
        deferred(d),
        result(nullptr) {};

    virtual ~AsyncContext() {}
};

struct NapiSEOmaCommon {
    static std::string keyCode;
    static std::string sePermDesc;

    template<typename T>
    static napi_value JSOmaClassConstructor(napi_env env, napi_callback_info info);

    static napi_value CreateUndefined(napi_env env);
    static std::string BuildErrorMessage(int errCode,
                                         std::string funcName,
                                         std::string forbiddenPerm,
                                         std::string paramName,
                                         std::string expertedType);
    static napi_value GenerateBusinessError(const napi_env &env, int errCode, const std::string &errMessage,
        const std::string &errData);
    static bool CheckSEStatusCodeAndThrow(const napi_env &env, int errCode, const std::string &funcName);
    static void CheckArgCountAndThrow(const napi_env &env, int argCount, int expCount);
    static bool ParseBytesVector(napi_env env, std::vector<unsigned char> &vec, napi_value args);
    static bool CheckArrayNumberAndThrow(const napi_env &env,
                                         const napi_value &param,
                                         const std::string &argName,
                                         const std::string &argType);
    static bool CheckStringAndThrow(const napi_env &env, const napi_value &param,
                                    const std::string &argName,
                                    const std::string &argType);
    static bool CheckNumberAndThrow(const napi_env &env,
                                    const napi_value &param,
                                    const std::string &argName,
                                    const std::string &argType);
    static void ThrowParameterError(const napi_env &env);
    static bool IsNumberArray(const napi_env &env, const napi_value &param);
    static bool IsObjectArray(const napi_env &env, const napi_value &param);
    static bool IsArray(const napi_env &env, const napi_value &param);
    static bool IsTargetValueType(const napi_env &env, const napi_value &param, napi_valuetype targetType);
    static bool ParseInt32Vector(napi_env env,
                                 napi_value param,
                                 const std::string &argName,
                                 std::vector<int32_t> &vec);
    static void Int32VectorToJS(napi_env env, std::vector<int32_t>& src, napi_value &result);
    static napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName);
    static napi_valuetype GetValueType(napi_env env, napi_value value);
    static std::string GetStringFromValue(napi_env env, napi_value value);
    static void ConvertStringToNumberArray(napi_env env, napi_value &result, std::string srcValue);
    static napi_value HandleAsyncWork(napi_env env, AsyncContext *context, const std::string &workName,
        napi_async_execute_callback execute, napi_async_complete_callback complete);
    static bool ParseString(napi_env env, std::string &value, napi_value args);
};

void DoAsyncCallbackOrPromise(const napi_env &env, AsyncContext *asyncContext, napi_value callbackValue);
void ThrowAsyncError(const napi_env &env, AsyncContext *asyncContext, int errCode, const std::string &errMsg,
    const std::string &data);
int BuildOutputErrorCode(int errCode);
} // namespace KITS
}  // namespace SE
}  // namespace OHOS
#endif
